﻿using System;
using System.Diagnostics;
using System.IO;
using System.Security.Permissions;

namespace WinRun
{
    public static class CommandProcessor
    {

        /// <summary>
        /// handles associating a command with an alias (if applicable) and executing that command
        /// </summary>
        /// <param name="aliasString">the name of the alias to run</param>
        /// <returns>0-successful execution, 1-failure to create process</returns>
        [SecurityPermission(SecurityAction.LinkDemand, Unrestricted = false)]
        public static int ProcessCommand(string aliasString)
        {
            /** handle paths **/
            if (Directory.Exists(aliasString))
            {
                var dirRet = ProcessDirectory(aliasString);
                return dirRet;
            }

            /** split command line in case there are arguments **/
            string[] aliasSplit = aliasString.Split(new char[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries);

            var a = new Alias();

            /** get the associated command for a registered alias **/
            string executeString = a.FindCommand(aliasSplit[0]);

            if (executeString.Length > 0 || aliasString.Contains("->"))
            {
                ProcessAlias(executeString, aliasSplit);
                return 0;
            }

            /** finally, handle regular programs **/
            var ret = ProcessProgram(aliasSplit);
            return ret;


        }

        private static int ProcessDirectory(string commandString)
        {
            var p = new Process();
            p.StartInfo.FileName = commandString;
            try
            {
                /** lets see if we can start this sucker **/
                p.Start();

                /** yup **/
                return 0;
            }
            catch (Exception)
            {
                /** nope **/
                return 1;
            }

        }

        /// <summary>
        /// Used to process chain commands
        /// </summary>
        /// <param name="commandString">the command line associated with this alias</param>
        /// <remarks>commands are seperated from each other buy the '->' string</remarks>
        private static int ProcessChain(string commandString)
        {
            /** seperate the chain items **/
            string[] delim = { "->" };
            string[] chain = commandString.Split(delim, StringSplitOptions.None);
            int procRet = 0;

            /** now go through and attempt to execute each one **/
            for (int i = 0; i < chain.Length; i++)
            {
                procRet = ProcessCommand(chain[i]);
            }

            return procRet;
        }

        /// <summary>
        /// Handle any commands that have been identified to be an alias
        /// </summary>
        /// <param name="commandString">the execution string</param>
        /// <param name="args">any arguments attached to command, including chain operator</param>
        /// <returns>0=success, 1 = fail</returns>
        private static int ProcessAlias(string commandString, string[] args)
        {
            var p = new Process();
            /** check to see if this is a chain of commands **/
            if (args[0].Contains("->"))
            {
                /** these are handled differently **/
                int chainRet = ProcessChain(args[0]);
                return chainRet;
            }
            else
            {
                if (args.Length > 1)
                {
                    p.StartInfo.Arguments = args[1];
                }
                p.StartInfo.FileName = commandString;

                try
                {
                    /** lets see if we can start this sucker **/
                    p.Start();

                    /** yup **/
                    return 0;
                }
                catch (Exception)
                {
                    /** nope **/
                    return 1;
                }


            }
        }

        /// <summary>
        /// If the user wants a standard program to run...
        /// </summary>
        /// <param name="args">command line</param>
        /// <returns>0=success, 1= fail</returns>
        private static int ProcessProgram(string[] args)
        {
            var p = new Process();
            string pth;

            if (args.Length > 1)
            {
                /** contains args **/
                pth = Path.GetFullPath(args[0] + " " + args[1]);
            }
            else
            {
                pth = Path.GetFullPath(args[0]);
            }
            

            if (File.Exists(@pth))
            {
                p.StartInfo.FileName = pth;
            }
            else
            {
                p.StartInfo.FileName = args[0];
            }

            if (args.Length > 1)
            {
                /** we have arguments...assign em **/
                p.StartInfo.Arguments = args[1];
            }

            try
            {
                /** lets see if we can start this sucker **/
                p.Start();

                /** yup **/
                return 0;
            }
            catch (Exception)
            {
                /** nope **/
                return 1;
            }

        }

    }
}
